home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr10
/
184_01.zip
/
FL3.MAC
< prev
next >
Wrap
Text File
|
1993-06-13
|
13KB
|
535 lines
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;
;This file contains the third of three patches to the
;source code for FLTLIB to enable use of the AMD9511
;(Intel 8231A) for floating point multiply/divide
;and MATHLIB functions.
;N.T.Carnevale 8/84.
;
;
;See accompanying documentation. Other useful information
;is in my article "Faster floating point math," which appeared
;on pp.46-54 of the Nov/Dec 1985 issue of Micro/Systems Journal.
;
;Use the following code to replace the source of the FLTLIB
;section of FLOATLIB.ASM from the line labelled fmult3:
;through the line just before label pophrt:
;
;
;
CR EQU 0DH
LF EQU 0AH
BDOS EQU 5
BOOT EQU 0
PSTRNG EQU 9
;
;
;send message to console
PRMSG:
PUSH PSW
PUSH B
PUSH D
PUSH H
MVI C,PSTRNG
CALL BDOS
POP H
POP D
POP B
POP PSW
RET
;
;**************************************************************
;
;
;Port addresses
;
BASE EQU 050H ;base address of Compupro SS1 board
CREG EQU BASE+9 ;location of 9511's control & data ports
DREG EQU BASE+8
;
;
;FPP error codes
;
ERRBITS EQU 1EH ;the status register's error bits
OVRFLO EQU 2 ;overflow
UNRFLO EQU 4 ;underflow
NEGARG EQU 8 ;negative argument to sqrt or log function
DIVZER EQU 10H ;divide by zero
TOOBIG EQU 18H ;arg of asin, acos, or exp too big
;
;
;FPP command codes
;
FMUL EQU 12H
FDIV EQU 13H
XCHF EQU 19H ;swap top two locations in fpp's stack
FSQRT EQU 1
FSIN EQU 2
FCOS EQU 3
FTAN EQU 4
FASIN EQU 5
FACOS EQU 6
FATAN EQU 7
FLOG EQU 8 ;log base 10
FLN EQU 9 ;natural logarithm
FEXP EQU 0AH ;e^x
FPWR EQU 0BH ;x^y
;
;**************************************************************
;**************************************************************
;
;
;note: timing indicated for some of the following
;
;This block converts c80 float in BD to FPP format, then loads it into FPP.
;If out of range for FPP, aborts with warning.
;
;Data format conversion routine C2AMD--
;converts c80's float to amd's fp format.
;Based on suggestions by J.Shook, Electronics Lab, Dept.of Chemistry,
;SUNY Stony Brook
;
;Floating point formats
;----------------------
;C80 stores floats as:
; mantissa sign in C7
; mantissa = 24 bit two's complement in CDE,
; with bit 23 assumed = 1.
; exponent is added to 128 (80H) and stored in B.
; If the number is 0, B=0.
;
;FPP stores floats as:
; mantissa sign in B7
; mantissa = 24 bit two's complement in CDE,
; with bit 23 = 1. However,
; the value 0 is represented by BD=0.
; exponent sign in B6
; exponent in B5-B0 (only 6 bits).
;
;
;Call with value to convert in BD.
C2AMD:
MOV A,B ; 4
ORA A ; 4
JZ FPPZERO ;10--B=0 implies x=0
;does exponent lie in FPP's range?
CPI 64+80H ; 7
JNC EXPHI ;10--exceeds 2^63
CPI -64+80H ; 7
JC EXPLO ;10--smaller than 2^-64
;exponent ok, proceed
SUI 80H ; 7--corrects exponent
ANI 7FH ; 7--mask out hi bit of B
MOV B,A ; 4-- and save til later
MOV A,C ; 4
ANI 80H ; 7--isolate mantissa sign bit
ORA B ; 4--fix mantissa sign bit for FPP
MOV B,A ; 4--done with B
;take care of C
MVI A,80H ; 7
ORA C ; 4--set hi bit of C
MOV C,A ; 4
JMP LOADFPP ;10--put data in FPP
;114 t cycles @ 4mHz = 28.5usec
;
FPPZERO: ;x=0
XRA A
MOV C,A
MOV D,A
MOV E,A
;a short cut, time not calculated
;fall through to next routine
;
;
;Data transfer routine
;LOADFPP puts BD into fpp
LOADFPP:
MOV A,E ; 4
OUT DREG ;11
MOV A,D ; 4
OUT DREG ;11
MOV A,C ; 4
OUT DREG ;11
MOV A,B ; 4
OUT DREG ;11
RET ;10
;70 t cycles = 17.5usec
;
;TOTAL TIME for C2AMD & LOADFPP = 46usec
;
;**************************************************************
;
;
;C2AMD found float to be out of range for FPP--warn & abort
EXPHI:
LXI D,HIMSG
JMP ERREXIT
EXPLO:
LXI D,LOMSG
ERREXIT:
CALL PRMSG
JMP BOOT ;bail out!
;
;
HIMSG: DB CR,LF,'float --> FPP exponent overflow ( > 2^63)$'
LOMSG: DB CR,LF,'float --> FPP exponent underflow ( < 2^-64)$'
;
;**************************************************************
;**************************************************************
;
;
;
;FLD1 gets 1 float from the stack, puts it into fpp,
;and DOES NOT restore stack. Called by "intrinsic"
;float arithmetic operations, e.g. fpmul and fpdiv.
FLD1:
POP H ;10--return addr for this block
SHLD RETADR ;16
POP H ;10--return addr for calling function
POP D ;10
POP B ;10--BD = argument
CALL C2AMD ;17--convert format & load FPP
;
PUSH H ;11--restore return address of calling function
LHLD RETADR ;16--return to calling function
PCHL ; 4-- without disturbing stack
;104 t cycles = 26usec, + 46 for C2AMD = 72usec
;
;**************************************************************
;
;
;FLOAD1 gets 1 float from the stack, puts it into fpp,
;and restores stack for c80. Called by "user-defined"
;functions, not by fpmul or fpdiv.
FLOAD1:
POP H ;10--return addr for this block
SHLD RETADR ;16
POP H ;10--return addr for calling function
POP D ;10
POP B ;10--BD = argument
CALL C2AMD ;17--convert format & load FPP
;fix stack for c80
PUSH H ;11
PUSH H ;11
PUSH H ;11--restore return address of calling function
LHLD RETADR ;16--return to calling function
PCHL ; 4-- without disturbing stack
;126 t cycles = 31.5usec, + 46 for C2AMD = 77.5usec
;
;**************************************************************
;
;
;FLOAD2 gets 2 floats from the stack, puts them into fpp,
; and restores the stack for c80
FLOAD2:
POP H ;10--return addr for this block
SHLD RETADR ;16
POP H ;10--return addr for calling function
POP D ;10
POP B ;10--BD = second argument
CALL C2AMD ;17--convert format & load FPP
POP D ;10
POP B ;10--BD = first argument
CALL C2AMD ;17
;fix stack for c80
PUSH H ;11 x 5 = 55
PUSH H
PUSH H
PUSH H
PUSH H ;restore return address of calling function
LHLD RETADR ;16--return to calling function
PCHL ; 4-- without disturbing stack
;185 t cycles = 46.25usec, + 2 * 46 (for C2AMD) = 138.25usec
;
RETADR: DS 2 ;used by all FPP load routines
;
;**************************************************************
;**************************************************************
;
;
;
;fpmask() allows the user to specify which error bits
;are tested for error detection. The argument to fpmask
;becomes the ERRMASK that is ANDed with the status word
;to detect a hardware (FPP) error.
PUBLIC fpmask
fpmask:
POP H ;return address
POP B ;argument
PUSH B ;fix stack
PUSH H
MOV A,C ;get the user-specified error mask
AN╔ ERRBIT╙ ╗ anΣ masδ ou⌠ al∞ bu⌠ thσ genuinσ erro≥ bits
STA ERRTEST+1
RET
;
;**************************************************************
;
;
;FPP Error handling routine
;print message according to what sort of error occurred
FPERR:
LXI D,EMSG0
CALL PRMSG ;print general message
MOV C,A ;save error code
MVI B,MSGPTR-ETYPES ;# of codes to check
LXI H,ETYPES ;M=first code in the list
LXI D,MSGPTR ;(DE) = address that contains
; location of message for first error code
ERCHEK:
ANA M
JMP ERMATCH
MOV A,C ;restore error code
INX H ;advance to next code and message
INX D
INX D
DCR B
JNZ ERCHEK ;more codes to test
;should never fall through, but if it does, will print 'huh?'
;
ERMATCH:
XCHG ;(HL) holds address of error message
MOV E,M
INX H
MOV D,M
JMP ERREXIT
;
;
EMSG0: DB CR,LF,,LF,'FPP error: $'
EMSG1: DB 'overflow$'
EMSG2: DB 'underflow$'
EMSG3: DB 'sqrt or log of negative number$'
EMSG4: DB 'divide by 0$'
EMSG5: DB 'argument of asin, acos, or exp too large$'
EMSGX: DB 'huh?$' ;should never occur!
;
;
ETYPES: DB OVRFLO,UNRFLO,TOOBIG,NEGARG,DIVZER
MSGPTR: DW EMSG1,EMSG2,EMSG5,EMSG3,EMSG4,EMSGX
;
;**************************************************************
;**************************************************************
;
;
;Next come the hardware floating point routines themselves.
;Thσ multiplcatioε routinσ contain≤ mos⌠ oµ wha⌠ thσ
;other routines use, so it is listed first.
PUBLIC fpmul
fpmul:
;Note: for fp multiply and divide,
;c80 passes the first arg in the stack, the second in BD.
;For the intrinsic multiply and divide operations,
;the calling program does NOT have to remove args
;from the stack upon return! This is quite different from
;the situation with user-defined functions.
;
;take 2nd arg from BD, convert to amd format, and pass to fpp
CALL C2AMD ;17
;take 1st arg from stack, convert format, and pass to fpp
CALL FLD1 ;17
;send command, test for error, return with result in BD
MVI A,FMUL ; 7
;fall through to DOIT-ERRTEST-GETIT-AMD2C
;
;
;DOIT-GETIT starts an FPP operation, tests for error,
;gets the result & converts to c80 format
;
;send command in A to FPP
DOIT: OUT CREG ;11--send command
WAIT: IN CREG ;10
ORA A ; 4
JM WAIT ;10--until done
;11 + n*24 t cycles = 2.75 + 6n usec (X)
;
;A contains error code
ERRTEST:
ANI ERRBITS ; 7--default = test all error bits
JNZ FPERR ;10--if error found, else fall through to GETIT
;
;get top of fpp's stack into BD
GETIT:
IN DREG ;10
MOV B,A ; 4
IN DREG ;10
MOV C,A ; 4
IN DREG ;10
MOV D,A ; 4
IN DREG ;10
MOV E,A ; 4
;
;Fall through to AMD2C, which converts FPP format in BD
;to c80 float
;AMD2C is based on suggestions by J.Shook, Electronics Lab,
;Dept.of Chemistry, SUNY Stony Brook
;
AMD2C:
MOV A,C ; 4
ORA A ; 4
JP C80ZERO ;10--bit 7=0 implies value is 0
;take care of mantissa sign
XRA B ; 4--complements bit 7 of B, among other things
ANI 80H ; 7--mask out all the garbage
XR┴ ├ ╗ 4--hΘ bi⌠ oµ ├ wa≤ ▒ iε AM─ format¼ s∩ this
MOV C,A ; 4-- sets the hi bit of C to mantissa sign
;take care of exponent sign
MVI A,40H ; 7
ANA B ; 4--is exponent negative?
MOV A,B ; 4
JZ POSEXP ;10--no, set hi bit to 1 (add 128)
ANI 7FH ; 7-- yes, mask out hi bit
MOV B,A ; 4
RET ;10
;
POSEXP:
ORI 80H ;set hi bit for positive exponent
MOV B,A
RET
;format conversion delay identical whether exponent is + or -
;
C80ZERO:
XRA A
MOV B,A
RET
;short cut--no time calculated
;
;(DOIT-ERRTEST-GETIT-AMD2C takes 156 t cycles
; = 39usec, + X (for operation))
;
;41 t cycles = 10.25usec, + 46 (C2AMD) + 72 (FLD1) + 39
; + X (DOIT) = 167.25 + X usec
;
;float sqrt(x) float x;
PUBLIC sqrt
sqrt:
CALL FLOAD1
MVI A,FSQRT
JMP DOIT
;float sin(x) float x;
PUBLIC sin
sin:
CALL FLOAD1
MVI A,FSIN
JMP DOIT
;float cos(x) float x;
PUBLIC cos
cos:
CALL FLOAD1
MVI A,FCOS
JMP DOIT
;float tan(x) float x;
PUBLIC tan
tan:
CALL FLOAD1
MVI A,FTAN
JMP DOIT
;float asin(x) float x; /* arc sin in radians */
PUBLIC asin
asin:
CALL FLOAD1
MVI A,FASIN
JMP DOIT
;float acos(x) float x;
PUBLIC acos
acos:
CALL FLOAD1
MVI A,FACOS
JMP DOIT
;float atan(x) float x;
PUBLIC atan
atan:
CALL FLOAD1
MVI A,FATAN
JMP DOIT
;float log(x) float x; /* log10 */
PUBLIC log
log:
CALL FLOAD1
MVI A,FLOG
JMP DOIT
;float ln(x) float x; /* log e */
PUBLIC ln
ln:
CALL FLOAD1
MVI A,FLN
JMP DOIT
;float exp(x) float x;
PUBLIC exp
exp:
CALL FLOAD1
MVI A,FEXP
JMP DOITè
;float pwr(x,y) float x,y; /* x to the yth power */
PUBLIC pwr
pwr:
CALL FLOAD2
;
MVI A,XCHF
OUT CREG ;11--send command
PWAIT: IN CREG ;10
ORA A ; 4
JM PWAIT ;10--until done
;
MVI A,FPWR
JMP DOIT
;
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;briefly back to the original source for fltlib--
;
; C/80 3.0 (7/7/83) - (c) 1983 Walter Bilofsky - used by permission
;
pophrt: POP H
RET
;
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;
div10.: CALL movrf. ;get facl_2 into BC, facl_ into DE
CALL C2AMD ;load 1st arg into fpp
LXI B,8420H
LXI D,0
CALL C2AMD ;load fpp with "10"
MVI A,FDIV
CALL DOIT ;return with result in BCDE
PUSH DE ;in case needed later
;save DE in facl_ & BC in facl_2,
; so ftoa gets proper value
CALL movfr. ;note: destroys DE
POP DE
RET ;previously fell through to fpdiv
;
;the fdiv: routine is replaced by fpdiv:, and muldiv: is not needed
PUBLIC fpdiv
fpdiv:
;take 2nd arg from BD, convert to amd format, and pass to fpp
CALL C2AMD ;17
;take 1st arg from stack, convert format, and pass to fpp
CALL FLD1 ;17
;swap fpp's A and B registers
MVI A,XCHF ; 7
OUT CREG ;11--send command
DWAIT: IN CREG ;10
ORA A ; 4
JM DWAIT ;10--until done
;send command, test for error, return with result in BD
MVI A,FDIV ; 7
JMP DOIT ;10
;takes 169.75usec + X plus delay for register swap
;END OF MODIFICATIONS TO FLTLIB.MAC<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;back to the original code again at mul10.:
mul10.: CALL movrf.
;
;END OF FL3.MAC